﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;

using Lib;
using System.Diagnostics;
using System.Threading;
namespace AlgoApriori
{
    public partial class AssosciationRules : Form
    {
        public Control tabap = new Control();
        public Control tabfp = new Control();
        public Control tabch = new Control();

        public AssosciationRules()
        {
            InitializeComponent();
            tabap = tabApriori;
            tabfp = tabFPGrowth;
            tabch = tabCharm;
            tabap.Enabled = false;
            tabfp.Enabled = false;
            tabch.Enabled = false;

        }

        public DataTable dt;
        public double MinSup = 0;
        public double MinConf = 0;
        public int algo = 0;

        public List<string> MissingValues = new List<string>();
        public TransactionData database = new TransactionData();
        public List<FrequentItem> fIs = new List<FrequentItem>();
        public List<Transaction> trans = new List<Transaction>();
        public List<DataAttribute> att = new List<DataAttribute>();

        #region Apriori

        private void btnRun_Click(object sender, EventArgs e)
        {
            lblStatus.Text = "";
            if (txtMinSub.Text == "" || txtMinconf.Text == "" || txtMinconf.Text == "" && txtMinSub.Text == "" || database.NumTrans == 0)
            {
                MessageBox.Show("Input is not enough!");
                if (txtMinSub.Text == null)
                {
                    txtMinSub.Focus();
                }

                else
                {
                    txtMinconf.Focus();
                }

            }
            else
            {
                btnRun.Enabled = false;
                lblStatus.Text = "Running ..... ";
                algo = 1;
                rtxtFrequent.Clear();
                rtxtRules.Clear();
                Thread a = new Thread(new ThreadStart(DoApriori));
                a.Start();
            }
        }

        private void DoApriori()
        {
            Apriori ap = new Apriori(database, double.Parse(txtMinSub.Text) * database.NumTrans / 100);
            Stopwatch watch = new Stopwatch();
            watch.Start();
            List<FrequentItem> Fis = new List<FrequentItem>();
            ap.RunAlgoApriori();
            Fis = ap.FI;
            Rules rule = new Rules(database, Fis, double.Parse(txtMinconf.Text) / 100);
            rule.Simple_AR2(Fis);
            //Fis.FindAll(y => y.Name.Count >= 2).ForEach(x => rule.GenRules(x, x));
            watch.Stop();
            foreach (var fi in Fis.OrderBy(x => x.Name.Count()))
            {
                string str = fi.ToString() + "\n";
                ShowResultToRtxt(rtxtFrequent, str);
            }
            SaveToTxt(rtxtRules, Fis, rule.AssiationRules, watch, txtMinSub, txtMinconf);
        }
        #endregion

        #region FP_growth

        private void btnRunFP_Click(object sender, EventArgs e)
        {
            lblStatus.Text = "";

            if (txtFPMinconf.Text == "" || txtMinSupFP.Text == "" || txtFPMinconf.Text == "" && txtMinSupFP.Text == "")
            {
                if (txtMinSupFP.Text == null)
                {
                    MessageBox.Show("Input is not enough!");
                    txtMinSupFP.Focus();
                }

                else
                {
                    MessageBox.Show("Input is not enough!");

                    txtFPMinconf.Focus();
                }

            }
            else
            {
                algo = 2;
                btnRunFP.Enabled = false;
                lblStatus.Text = "Running ..... ";
                rtxtFIFPGrowth.Clear();
                txtFPReslt.Clear();
                Thread b = new Thread(new ThreadStart(DoFpGrowth));
                b.Start();
            }
        }

        private void DoFpGrowth()
        {
            FPAlgo fp = new FPAlgo(double.Parse(txtMinSupFP.Text) * database.NumTrans / 100, database);
            FPTree tree = new FPTree();
            List<FrequentItem> fis = new List<FrequentItem>();
            Stopwatch watch = new Stopwatch();
            watch.Start();
            tree = fp.createFptree(database);
            fp.FP_growth(tree);
            fis = fp.FI;
            Rules rule = new Rules(database, fis, double.Parse(txtFPMinconf.Text) / 100);
            rule.Simple_AR2(fis);
            watch.Stop();
            foreach (var fi in fis.OrderBy(x => x.Name.Count()))
            {
                string s = "";
                foreach (var name in fi.Name)
                {
                    s += name.AttName + ": " + name.Name + " \t ";
                }
                s += fi.Supp + "\n";
                ShowResultToRtxt(rtxtFIFPGrowth, s);
            }

            SaveToTxt(txtFPReslt, fis, rule.AssiationRules, watch, txtMinSupFP, txtFPMinconf);
        }

        #endregion

        #region Charm
        private void btnRunITAlgo_Click(object sender, EventArgs e)
        {
            lblStatus.Text = "";

            if (txtminsupIT.Text == "" || txtMincofCharm.Text == "" || txtminsupIT.Text == "" && txtMincofCharm.Text == "")
            {
                MessageBox.Show("Input is not enough!");
                if (txtminsupIT.Text == "")
                {
                    txtminsupIT.Focus();
                }

                else
                {
                    txtMincofCharm.Focus();
                }

            }
            else
            {
                algo = 3;
                btnRunITAlgo.Enabled = false;
                lblStatus.Text = "Running ..... ";
                rtxtFICharm.Clear();
                rtxtCharmAR.Clear();
                Thread c = new Thread(new ThreadStart(DoCharm));
                c.Start();
            }

        }

        private void DoCharm()
        {
            ITAlgo it = new ITAlgo(int.Parse(txtminsupIT.Text) * database.NumTrans / 100, database);
            Dictionary<List<TransactionValue>, int> Fi = new Dictionary<List<TransactionValue>, int>();
            List<FrequentItem> Fis = new List<FrequentItem>();
            Stopwatch watch = new Stopwatch();
            watch.Start();
            Fis = it.Charm();
            Rules rule = new Rules(database, Fis, double.Parse(txtMincofCharm.Text) / 100);
            rule.Extract_Ar(Fis.OrderBy(x => x.Name.Count).ToList());
            watch.Stop();
            foreach (var fi in Fis.OrderBy(x => x.Name.Count()))
            {
                string s = "";
                fi.Name.ForEach(x => s += x.AttName + ": " + x.Name + "   ");
                s += fi.Supp + "\n";
                ShowResultToRtxt(rtxtFICharm, s);
            }
            SaveToTxt(rtxtCharmAR, Fis, rule.AssiationRules, watch, txtminsupIT, txtMincofCharm);
        }
        #endregion

        #region Save to txt

        public void SaveToTxt(RichTextBox rtxt, List<FrequentItem> fi, List<string> ar, Stopwatch watch, TextBox minsup, TextBox mincof)
        {
            string str = "";
            str = String.Format("{0} - minsup = {1}%({2})  - mincof = {3}%\n", database.DataName, minsup.Text, (double.Parse(minsup.Text) * database.NumTrans / 100).ToString(), mincof.Text);
            ShowResultToRtxt(rtxt, str);
            string tabtext = "";

            if (algo == 1)
            {
                tabtext = "Apriori";
            }
            else
            {
                if (algo == 2)
                    tabtext = "FP_Grownth";
                else
                    tabtext = "Charm";
            }
            str = tabtext + "\n";
            ShowResultToRtxt(rtxt, str);
            str = String.Format("Attributes: {0} Instances: {1}\nTime:{2} s\n", database.Attributes.Count.ToString(), database.NumTrans.ToString(), watch.Elapsed.Milliseconds);
            ShowResultToRtxt(rtxt, str);
            str = "Num FIs: " + fi.Count.ToString() + "\n";
            ShowResultToRtxt(rtxt, str);
            str = "Num rules: " + ar.Count().ToString() + "\n";
            ShowResultToRtxt(rtxt, str);
            str = "_____________________________________________________________________\n";
            ShowResultToRtxt(rtxt, str);
            int i = 1;
            foreach (var item in ar)
            {
                string s = string.Format("{0}|  ", i++) + item + "\n";
                ShowResultToRtxt(rtxt, s);
            }
            string fileName = string.Format("{0}-{1}-minsup({2}%)-mincof({3}%)-{4}.txt", String.Format("{0}{1}{2}{3}{4}", DateTime.Now.Day.ToString(), DateTime.Now.Month.ToString(), DateTime.Now.Year.ToString(), DateTime.Now.Hour.ToString(), DateTime.Now.Second.ToString()), database.DataName, minsup.Text, mincof.Text, tabtext);
            var desktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            var fullPath = Path.Combine(desktopFolder, fileName);
            SaveFileRtxt(rtxt, fullPath);
        }
        #endregion

        #region Read Data'Attribute

        private void btnDP_Click(object sender, EventArgs e)
        {
            dt = new DataTable();
            database = new TransactionData();
            Stream myStream = null;

            OpenFileDialog open = new OpenFileDialog();
            open.Filter = "All files (*.*)|*.*";
            open.RestoreDirectory = true;
            if (open.ShowDialog() == DialogResult.OK)
            {
                database.DataName = open.SafeFileName;
                try
                {
                    if ((myStream = open.OpenFile()) != null)
                    {
                        using (myStream)
                        {
                            database.DataName = open.FileName.Substring(open.FileName.LastIndexOf("\\") + 1); ;
                            using (var read = new StreamReader(myStream))
                            {
                                att = new List<DataAttribute>();
                                trans = new List<Transaction>();

                                string[] firstline = read.ReadLine().Split(',');
                                for (int i = 0; i < firstline.Length; i++)
                                {
                                    att.Add(new DataAttribute(firstline[i], null, i));
                                }
                                string line;
                                int key = 1;
                                while ((line = read.ReadLine()) != null)
                                {
                                    string[] datavalue = line.Split(',');
                                    Transaction tran = new Transaction(key, datavalue);
                                    database.Add(tran);
                                    key++;
                                }
                            }
                            database.Attributes = att;
                            UpdateAttValues();
                            FilterAttribute();
                            dt = database.ConvertToDataTable(database);
                            dgwDataPreprocessing.DataSource = dt;
                            tabap.Enabled = true;
                            tabfp.Enabled = true;
                            tabch.Enabled = true;
                            lblAttributes.Text = att.Count.ToString();
                            lblinstances.Text = database.NumTrans.ToString();
                            lblDataName.Text = database.DataName;
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void UpdateAttValues()
        {
            List<DataAttribute> atts = database.Attributes;
            List<Transaction> trans = database.Transactions;
            foreach (var att in atts)
            {
                List<TransactionValue> transValue = new List<TransactionValue>();
                foreach (var tran in trans)
                {
                    tran.Value[att.Index].AttIndex = att.Index;
                    tran.Value[att.Index].AttName = att.AttributeName;
                    transValue.Add(tran.Value[att.Index]);
                }
                foreach (var t in transValue)
                {
                    if (att.AttValue.Find(x => x.Name == t.Name) != null)
                        att.AttValue.Find(x => x.Name == t.Name).Count++;
                    else
                    {
                        att.AttValue.Add(new TransactionValue(t.Name, t.AttIndex, t.AttName));
                    }
                }
            }
        }

        private void FilterAttribute()
        {
            dgwTestATT.DataSource = null;
            string[] attname = database.Attributes.Select(x => x.AttributeName).ToArray();
            var bindable = from name in attname select new { Attributes = name };
            dgwTestATT.DataSource = bindable.ToList();
        }

        private void dgwTestATT_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            string a = dgwTestATT.SelectedCells[0].Value.ToString();
            DataAttribute dataAtt = database.GetAttribute(a);
            List<TransactionValue> l = dataAtt.AttValue; 
            var bindable = from name in l select new { AttValues = name.Name, Count = name.Count };
            dgwTestValue.DataSource = bindable.ToList();
        }

        private void btnReplaceMissing_Click(object sender, EventArgs e)
        {

        }
        #endregion

        #region System Tray

        private void Form1_Resize(object sender, EventArgs e)
        {
            if (FormWindowState.Minimized == this.WindowState)
            {
                nicSystemTray.Visible = true;
                nicSystemTray.ShowBalloonTip(50);
                this.Hide();
            }
            else if (FormWindowState.Normal == this.WindowState)
            {
                nicSystemTray.Visible = false;
            }
        }

        private void nicSystemTray_Click(object sender, EventArgs e)
        {
            nicSystemTray.Visible = false;
            this.Show();
            this.WindowState = FormWindowState.Normal;
        }
        #endregion

        #region Thread
        private static void SaveFileRtxt(RichTextBox rtxt, string path)
        {
            if (rtxt.InvokeRequired)
            {
                rtxt.BeginInvoke(new MethodInvoker(() => SaveFileRtxt(rtxt, path)));
            }
            else
            {
                rtxt.SaveFile(path, RichTextBoxStreamType.PlainText);
            }
        }

        private static void ShowResultToRtxt(RichTextBox rtxt, string str)
        {
            if (rtxt.InvokeRequired)
            {
                rtxt.BeginInvoke(new MethodInvoker(() => ShowResultToRtxt(rtxt, str)));
            }
            else
            {
                rtxt.Text += str;
            }
        }

        private static void ShowProgressBar(ProgressBar bar, int i)
        {
            if (bar.InvokeRequired)
            {
                bar.BeginInvoke(new MethodInvoker(() => ShowProgressBar(bar, i)));
            }
            else
            {
                bar.Value = i;
            }
        }

        private void rtxtRules_TextChanged(object sender, EventArgs e)
        {
            btnRun.Enabled = !string.IsNullOrEmpty(rtxtRules.Text);
            lblStatus.Text = "Finish!";

        }

        private void rtxtCharmAR_TextChanged(object sender, EventArgs e)
        {
            btnRunITAlgo.Enabled = !string.IsNullOrEmpty(rtxtCharmAR.Text);
            lblStatus.Text = "Finish!";

        }

        private void txtFPReslt_TextChanged(object sender, EventArgs e)
        {
            btnRunFP.Enabled = !string.IsNullOrEmpty(txtFPReslt.Text);
            lblStatus.Text = "Finish!";

        }




        #endregion









    }

}
